<template>
  <div class="source-edit">
    <div class="source-header"></div>
    <steve-content v-model:height="steveContentHeight" :other-height="steveContentOtherHeight">
      <t-row>
        <t-col :flex="0">
          <div class="source-edit-setting" :style="{ height: steveContentHeight + 'px' }">
            <div class="source-edit-setting__top">
              <t-popup v-if="deviceExport" placement="bottom-right" trigger="click" show-arrow>
                <t-button theme="default" shape="square" variant="text">
                  <steve-icon name="debug" />
                </t-button>
                <template #content>
                  <div class="debug-title">{{ $t('pages.source.setting.debug') }}</div>
                  <div class="debug-list">
                    <div class="debug-item">
                      <div class="debug-item__name">{{ $t('pages.source.debug.searchKeyword') }}</div>
                      <div class="debug-item__switch">
                        <t-input v-model="searchKeyword" />
                      </div>
                    </div>
                    <div class="debug-item">
                      <div class="debug-item__name">{{ $t('pages.source.debug.displayedTheLeft') }}</div>
                      <div class="debug-item__switch">
                        <t-switch v-model="showDebugLeft" />
                      </div>
                    </div>
                    <div class="debug-item">
                      <div class="debug-item__name">{{ $t('pages.source.debug.displayedTheRight') }}</div>
                      <div class="debug-item__switch">
                        <t-switch v-model="showDebugRight" />
                      </div>
                    </div>
                  </div>
                </template>
              </t-popup>
            </div>
            <div class="source-edit-setting__bottom">
              <t-tooltip v-if="deviceExport" placement="right" :content="$t('pages.source.setting.toPhone')">
                <t-button
                  theme="default"
                  shape="square"
                  variant="text"
                  :disabled="saveToPhoneLoading"
                  :loading="saveToPhoneLoading"
                  @click="onToPhone"
                >
                  <steve-icon v-if="!saveToPhoneLoading" name="upload" />
                </t-button>
              </t-tooltip>
              <t-tooltip v-if="deviceExport" placement="right" :content="$t('pages.source.setting.refresh')">
                <t-button
                  theme="default"
                  :disabled="!id || getInfoLoading"
                  shape="square"
                  variant="text"
                  :loading="getInfoLoading"
                  @click="onRefreshInfo"
                >
                  <steve-icon v-if="!getInfoLoading" name="refresh" />
                </t-button>
              </t-tooltip>
              <t-tooltip v-if="deviceExport" placement="right" :content="$t('layout.aceEditor.download')">
                <t-button
                  theme="default"
                  :disabled="!id || downloadMrsLoading"
                  shape="square"
                  variant="text"
                  :loading="downloadMrsLoading"
                  @click="onDownloadFileMrs"
                >
                  <steve-icon v-if="!downloadMrsLoading" name="download-mrs" />
                </t-button>
              </t-tooltip>
              <t-tooltip placement="right" :content="$t('pages.source.setting.name')">
                <t-button theme="default" shape="square" variant="text">
                  <steve-icon name="setting" />
                </t-button>
              </t-tooltip>
            </div>
          </div>
        </t-col>
        <!-- Form Edit -->
        <t-col v-if="!showDebugLeft" :flex="1">
          <div class="source-edit-form">
            <t-form ref="source-form" label-width="160px">
              <t-tabs v-model="formTabsValue" :data="localFormData" theme="card">
                <t-tab-panel value="base" :label="$t('pages.source.base.label')" :destroy-on-hide="false">
                  <div class="scrollable-container" :style="getHeightStyle">
                    <base-form :form-data="localFormData" />
                  </div>
                </t-tab-panel>
                <t-tab-panel value="search" :label="$t('pages.source.ruleSearch.label')" :destroy-on-hide="false">
                  <div class="scrollable-container" :style="getHeightStyle">
                    <search-form :form-data="localFormData" />
                  </div>
                </t-tab-panel>
                <t-tab-panel value="bookInfo" :label="$t('pages.source.ruleBookInfo.label')" :destroy-on-hide="false">
                  <div class="scrollable-container" :style="getHeightStyle">
                    <book-info-form :form-data="localFormData" />
                  </div>
                </t-tab-panel>
                <t-tab-panel value="chapter" :label="$t('pages.source.ruleChapter.label')" :destroy-on-hide="false">
                  <div class="scrollable-container" :style="getHeightStyle">
                    <chapter-form :form-data="localFormData" />
                  </div>
                </t-tab-panel>
                <t-tab-panel value="content" :label="$t('pages.source.ruleContent.label')" :destroy-on-hide="false">
                  <div class="scrollable-container" :style="getHeightStyle">
                    <content-form :form-data="localFormData" />
                  </div>
                </t-tab-panel>
                <t-tab-panel value="finder" :label="$t('pages.source.ruleFinder.label')" :destroy-on-hide="false">
                  <div class="scrollable-container" :style="getHeightStyle">
                    <finder-form :form-data="localFormData" />
                  </div>
                </t-tab-panel>
              </t-tabs>
            </t-form>
          </div>
        </t-col>
        <!-- Debug -->
        <t-col v-if="showDebugLeft || showDebugRight" :flex="1">
          <debug :height="steveContentHeight" :site-json="aceEditorJson" />
        </t-col>
        <!-- Ace Editor -->
        <t-col v-if="!showDebugRight" :flex="1" class="source-edit-json">
          <steve-ace-editor
            v-model:value="aceEditorJson"
            :height="steveContentHeight"
            @blur="onAceBlur"
            @focus="onAceFocus"
          />
        </t-col>
      </t-row>
    </steve-content>
    <div class="source-footer"></div>
  </div>
</template>
<script setup lang="ts">
import { deepCopy } from '@intlify/shared';
import { useLocalStorage } from '@vueuse/core';
import { saveAs } from 'file-saver';
import pako from 'pako';
import { isEmpty, isJSON } from 'validator';
import { computed, CSSProperties, reactive, ref, watch } from 'vue';
import { useRoute } from 'vue-router';

import { ApiSiteExport, ApiSiteInfo, ApiSiteSave } from '@/api/api';
import SteveAceEditor from '@/components/steveAceEditor/index.vue';
import SteveContent from '@/components/steveContent/index.vue';
import steveIcon from '@/components/steveIcon/index.vue';
import { localeKeys } from '@/config/global';
import { t } from '@/locales';
import BaseForm from '@/pages/source/edit/components/base.vue';
import BookInfoForm from '@/pages/source/edit/components/bookInfo.vue';
import ChapterForm from '@/pages/source/edit/components/chapter.vue';
import ContentForm from '@/pages/source/edit/components/content.vue';
import Debug from '@/pages/source/edit/components/Debug.vue';
import FinderForm from '@/pages/source/edit/components/finder.vue';
import SearchForm from '@/pages/source/edit/components/search.vue';
import { sourceRule, sourceRuleObjectField } from '@/pages/source/edit/sourceRule';
import {
  compressJSON,
  formatJSON,
  getArrayFieldToArray,
  getObjectPaths,
  getValueByPath,
  isDeviceExport,
  setValueByPath,
  showMessage,
  steveDeepCopy,
} from '@/utils/common';

// 是否来自设备
const deviceExport = ref(isDeviceExport());

// 组件高度
const steveContentHeight = ref(window.innerHeight);

// 其他的组件高度
const computedStyle = getComputedStyle(document.documentElement);
const tabsHeight = computedStyle.getPropertyValue('--td-comp-size-xxl');
const otherHeight = computedStyle.getPropertyValue('--td-comp-size-s');
const steveContentOtherHeight = ref(parseFloat(otherHeight) * 2);

// 获取组件高度
const getHeightStyle = computed((): CSSProperties => {
  return {
    height: `${steveContentHeight.value - parseFloat(tabsHeight)}px`,
  };
});

const saveToPhoneLoading = ref(false);
const getInfoLoading = ref(false);
const downloadMrsLoading = ref(false);

// 显示调试器
const showDebugLeft = ref(useLocalStorage(localeKeys.sourceDebug, 'none').value === 'left');
const showDebugRight = ref(useLocalStorage(localeKeys.sourceDebug, 'none').value === 'right');
watch(showDebugLeft, (v) => {
  useLocalStorage(localeKeys.sourceDebug, 'none').value = v ? 'left' : 'none';
  if (v && showDebugRight.value) {
    showDebugRight.value = false;
  }
});
watch(showDebugRight, (v) => {
  useLocalStorage(localeKeys.sourceDebug, 'none').value = v ? 'right' : 'none';
  if (v && showDebugLeft.value) {
    showDebugLeft.value = false;
  }
});

// 调试器搜索关键字
const searchKeyword = ref(useLocalStorage(localeKeys.sourceDebugSearch, '修仙'));

// 获取formData
const localFormData = reactive({
  version: 1,
  siteName: '',
  host: '',
  status: true,
  finderStatus: false,
});
deepCopy(steveDeepCopy(sourceRule), localFormData);

// 获取对象字段
const localSourceRuleObjectField = steveDeepCopy(sourceRuleObjectField);

// 顶部Tabs
const formTabsValue = ref('base');

// Ace编辑器的json数据
const aceEditorJson = ref('');

// 当前是否为ace编辑器编辑
const isAceEditing = ref(false);

// json路径数组
const valueIsJsonPaths = getObjectPaths(localSourceRuleObjectField);
const allJsonPaths = getObjectPaths(localFormData);

/**
 * form数据转Ace编辑器能显示的数据
 * @param v
 */
const formDataToAceJson = (v: any) => {
  // 深copy
  deepCopy(v, localSourceRuleObjectField);

  for (const path of valueIsJsonPaths) {
    const value = getValueByPath(localFormData, path.value);
    let jsonValue;
    if (typeof value === 'string') {
      jsonValue = !isEmpty(value) && isJSON(value) ? JSON.parse(value) : path.defaultValue;
    } else {
      jsonValue = value;
    }
    setValueByPath(localSourceRuleObjectField, path.value, jsonValue);
  }
  aceEditorJson.value = formatJSON(JSON.stringify(localSourceRuleObjectField));
};

/**
 * json数组转form数据
 * @param v
 */
const aceJsonToFormData = (v: any) => {
  if (isJSON(v)) {
    const json = JSON.parse(v);
    for (const path of allJsonPaths) {
      let value = getValueByPath(json, path.value);
      if (getArrayFieldToArray(valueIsJsonPaths, 'value').includes(path.value)) {
        if (typeof value === 'object') {
          value = Object.keys(value).length > 0 ? JSON.stringify(value) : '';
        } else if (typeof value === 'string') {
          value = path.defaultValue;
        }
      }
      setValueByPath(localFormData, path.value, value);
    }
  }
};

// 观察formData的变化
watch(localFormData, (v) => {
  // 如果是ace编辑器编辑则不操作
  if (isAceEditing.value) {
    return;
  }

  formDataToAceJson(v);
});

// 观察ace编辑器参数中的json变化
watch(aceEditorJson, (v) => {
  // 如果不是ace操作则不运行
  if (!isAceEditing.value) {
    return;
  }
  aceJsonToFormData(v);
});

// Ace编辑器获取焦点
const onAceFocus = () => {
  isAceEditing.value = true;
};

// Ace编辑器失去焦点
const onAceBlur = () => {
  isAceEditing.value = false;
};

// 同步至手机
const onToPhone = () => {
  saveToPhone();
};

// 刷新
const onRefreshInfo = () => {
  getInfo(true);
};

// 下载Mrs文件
const onDownloadFileMrs = () => {
  getFileMrs();
};

// 路由
const route = useRoute();

// 源ID
const id = ref(route.query.id);

// 编辑
if (id.value) {
  getInfo(false);
} else {
  // 进入页面先进行JSON格式化
  formDataToAceJson(localFormData);
}

/**
 * 获取源详情
 */
function getInfo(refresh: boolean = false) {
  getInfoLoading.value = true;
  ApiSiteInfo(id.value).then((data) => {
    getInfoLoading.value = false;
    if (data.ruleData) {
      data.ruleData.status = data.status == 1;
      data.ruleData.finderStatus = data.finderStatus == 1;
      aceJsonToFormData(compressJSON(JSON.stringify(data.ruleData)));
    } else {
      aceJsonToFormData(compressJSON(data.xpath));
    }
    if (refresh) {
      showMessage(t('pages.source.setting.refreshSuccess'));
    }
  });
}

/**
 * 下载mrs文件
 */
function getFileMrs() {
  downloadMrsLoading.value = true;
  ApiSiteExport(id.value).then((data) => {
    downloadMrsLoading.value = false;

    const cData = pako.gzip(data);
    const blob = new Blob([cData]);

    let fileName: string = '';
    if (localFormData) {
      fileName = `${localFormData.siteName}_v${localFormData.version}`;
    }
    saveAs(blob, `${fileName}.mrs`);
  });
}

// 保存到手机
function saveToPhone() {
  if (!localFormData.siteName) {
    showMessage(t('pages.source.sync.siteName'), 'error');
    return;
  }

  if (!localFormData.host) {
    showMessage(t('pages.source.sync.siteUrl'), 'error');
    return;
  }

  saveToPhoneLoading.value = true;
  ApiSiteSave(id.value, compressJSON(aceEditorJson.value), {
    status: localFormData.status ? 1 : 0,
    finderStatus: localFormData.finderStatus ? 1 : 0,
  }).then((data) => {
    saveToPhoneLoading.value = false;
    if (data > 0) {
      id.value = data;
      showMessage(t('pages.source.setting.syncToPhoneSuccess'));
    }
  });
}
</script>

<style lang="less" scoped>
.source-edit {
  overflow: hidden;
  border-radius: var(--td-radius-medium);

  &-setting {
    width: 60px;
    padding: var(--td-comp-paddingTB-s) 0;
    background: var(--td-bg-color-secondarycontainer);
    border-right: 1px solid var(--td-component-stroke);
    display: flex;
    justify-content: space-between;
    flex-direction: column;

    &__top,
    &__bottom {
      display: flex;
      flex-direction: column;
      align-items: center;

      :deep(.t-button + .t-button) {
        margin-left: 0;
        margin-top: var(--td-comp-margin-s);
      }
    }
  }

  &-json {
    //margin-left: var(--td-comp-margin-xs);
  }

  &-form {
    border-right: 1px solid var(--td-component-stroke);
  }

  .scrollable-container {
    overflow-y: auto;
  }
}

.debug {
  &-title {
    padding: var(--td-pop-padding-m);
    font-weight: bold;
  }

  &-list {
    padding: 0 var(--td-pop-padding-m);

    .debug-item {
      display: flex;
      flex-direction: row;
      padding: var(--td-pop-padding-m) 0;

      &__name {
        width: 140px;
        display: flex;
        align-items: center;
      }
    }
  }
}

.source-footer,
.source-header {
  padding: 0 var(--td-comp-paddingLR-xs);
  background: var(--td-bg-color-secondarycontainer);
  height: var(--td-comp-size-s);
}

.source-footer {
  border-top: 1px solid var(--td-component-stroke);
}

.source-header {
  border-bottom: 1px solid var(--td-component-stroke);
}
</style>
